﻿#if UNITY_IOS
using System;
using UnityEngine;
using System.Runtime.InteropServices;
using GMME.Model.Rtm.Req;
using GMME.Model.Rtm.Result;


namespace GMME
{
    class GameMediaEngineForIos : GameMediaEngine
    {
        // Native的引擎对象
        private IntPtr pgmePtr;
        private IntPtr unityPtr;
        private IGameMMEEventHandler callBackHandler;

        #region native callback delegate

        internal delegate void PGMEOnCreateCallback(IntPtr unityClient, int code, string msg);

        internal delegate void PGMEOnLeaveRoomCallback(IntPtr unityClient, string roomId, int code, string msg);

        internal delegate void PGMEOnJoinTeamRoomCallback(IntPtr unityClient, string roomId, int code, string msg);

        internal delegate void PGMEOnJoinNationalRoomCallback(IntPtr unityClient, string roomId, int code, string msg);

        internal delegate void PGMEOnJoinRangeRoomCallback(IntPtr unityClient, string roomId, int code, string msg);

        internal delegate void PGMEOnForbidPlayerCallback(IntPtr unityClient, string roomId, string openId,
            bool isForbidden, int code, string msg);

        // openIds原始的NSArray 转成string回调给上层
        internal delegate void PGMEOnForbidAllPlayersCallback(IntPtr unityClient, string roomId, string openIds,
            bool isForbidden, int code, string msg);

        internal delegate void PGMEOnMutePlayerCallback(IntPtr unityClient, string roomId, string openId, bool isMuted,
            int code, string msg);

        // openIds原始的NSArray 转成string回调给上层
        internal delegate void PGMEOnMuteAllPlayersCallback(IntPtr unityClient, string roomId, string openIds,
            bool isMuted, int code, string msg);

        internal delegate void PGMEOnPlayerOnlineCallback(IntPtr unityClient, string roomId, string openId);

        internal delegate void PGMEOnPlayerOfflineCallback(IntPtr unityClient, string roomId, string openId);

        internal delegate void PGMEOnDestoryCallback(IntPtr unityClient, int code, string msg);

        internal delegate void PGMEOnSpeakerDetectionExCallback(IntPtr unityClient, string userVolumeInfos);

        internal delegate void PGMEOnForbiddenByOwnerCallback(IntPtr unityClient, string roomId, string openIds,
            bool isForbidden);

        internal delegate void PGMEOnSwitchRoomCallback(IntPtr unityClient, string roomId, int code, string msg);

        internal delegate void PGMEOnTransferOwnerCallback(IntPtr unityClient, string roomId, int code, string msg);

        internal delegate void PGMEOnRemoteMicroStateChangedCallback(IntPtr unityClient, string roomId, string openId,
            bool isMute);

        internal delegate void PGMEOnVoiceToTextCallback(IntPtr unityClient, string text, int code, string msg);

        internal delegate void PGMEOnUploadAudioMsgFileCallback(IntPtr unityClient, string filepath, string fileId,
            int code, string msg);

        internal delegate void PGMEOnDownloadAudioMsgFileCallback(IntPtr unityClient, string filepath, string fileId,
            int code, string msg);

        internal delegate void PGMEOnRecordAudioMsgCallback(IntPtr unityClient, string filepath, int code, string msg);

        internal delegate void PGMEOnPlayAudioMsgCallback(IntPtr unityClient, string filepath, int code, string msg);

        internal delegate void PGMEOnStartDetectAudioFileCallback(IntPtr unityClient, string fileId, int code, string msg);

        internal delegate void PGMEOnAudioClipStateChangedNotifyCallback(IntPtr unityClient, string audioPlayStateInfo);

        #region rtm

        internal delegate void PGMEOnSubscribeRtmChannelCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnUnSubscribeRtmChannelCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnPublishRtmChannelMessageCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnPublishRtmPeerMessageCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnGetRtmChannelInfoCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnReceiveRtmChannelMessageCallback(IntPtr unityClient, string notify);

        internal delegate void PGMEOnReceiveRtmPeerMessageCallback(IntPtr unityClient, string notify);

        internal delegate void PGMEOnRtmConnectionChangedCallback(IntPtr unityClient, string notify);

        internal delegate void PGMEOnSetRtmChannelPlayerPropertiesCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnGetRtmChannelPlayerPropertiesCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnDeleteRtmChannelPlayerPropertiesCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnSetRtmChannelPropertiesCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnGetRtmChannelPropertiesCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnDeleteRtmChannelPropertiesCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnGetRtmChannelHistoryMessagesCallback(IntPtr unityClient, string result);

        internal delegate void PGMEOnRtmChannelPlayerPropertiesChangedCallback(IntPtr unityClient, string notify);

        internal delegate void PGMEOnRtmChannelPropertiesChangedCallback(IntPtr unityClient, string notify);

        #endregion

        #endregion

        #region native function

        [DllImport("__Internal")]
        internal static extern IntPtr InitHWPGMENative(IntPtr unityPtr);

        [DllImport("__Internal")]
        internal static extern void SetNativeCallbacks(IntPtr native,
            PGMEOnCreateCallback createCallback,
            PGMEOnLeaveRoomCallback leaveRoomCallback,
            PGMEOnJoinTeamRoomCallback joinTeamRoomCallback,
            PGMEOnJoinNationalRoomCallback joinNationalRoomCallback,
            PGMEOnForbidPlayerCallback forbidPlayerCallback,
            PGMEOnForbidAllPlayersCallback forbidAllPlayersCallback,
            PGMEOnMutePlayerCallback mutePlayerCallback,
            PGMEOnMuteAllPlayersCallback muteAllPlayersCallback,
            PGMEOnPlayerOnlineCallback playerOnlineCallback,
            PGMEOnPlayerOfflineCallback playerOfflineCallback,
            PGMEOnDestoryCallback destoryCallback,
            PGMEOnSpeakerDetectionExCallback speakerDetectionExCallback,
            PGMEOnForbiddenByOwnerCallback forbiddenByOwnerCallback,
            PGMEOnSwitchRoomCallback switchRoomCallback,
            PGMEOnTransferOwnerCallback transferOwnerCallback,
            PGMEOnVoiceToTextCallback voiceToTextCallback,
            PGMEOnRemoteMicroStateChangedCallback remoteMicroStateChangedCallback,
            PGMEOnUploadAudioMsgFileCallback uploadAudioMsgFileCallback,
            PGMEOnDownloadAudioMsgFileCallback downloadAudioMsgFileCallback,
            PGMEOnRecordAudioMsgCallback recordAudioMsgCallback,
            PGMEOnPlayAudioMsgCallback playAudioMsgCallback,
            PGMEOnAudioClipStateChangedNotifyCallback audioClipStateChangedNotifyCallback,
            PGMEOnJoinRangeRoomCallback joinRangeRoomCallback,
            PGMEOnSubscribeRtmChannelCallback onSubscribeRtmChannelCallback,
            PGMEOnUnSubscribeRtmChannelCallback onUnSubscribeRtmChannelCallback,
            PGMEOnPublishRtmChannelMessageCallback onPublishRtmChannelMessageCallback,
            PGMEOnPublishRtmPeerMessageCallback onPublishRtmPeerMessageCallback,
            PGMEOnGetRtmChannelInfoCallback onGetRtmChannelInfoCallback,
            PGMEOnReceiveRtmChannelMessageCallback onReceiveRtmChannelMessageCallback,
            PGMEOnReceiveRtmPeerMessageCallback onReceiveRtmPeerMessageCallback,
            PGMEOnRtmConnectionChangedCallback onRtmConnectionChangedCallback,
            PGMEOnSetRtmChannelPlayerPropertiesCallback onSetRtmChannelPlayerPropertiesCallback,
            PGMEOnGetRtmChannelPlayerPropertiesCallback onGetRtmChannelPlayerPropertiesCallback,
            PGMEOnDeleteRtmChannelPlayerPropertiesCallback onDeleteRtmChannelPlayerPropertiesCallback,
            PGMEOnSetRtmChannelPropertiesCallback onSetRtmChannelPropertiesCallback,
            PGMEOnGetRtmChannelPropertiesCallback onGetRtmChannelPropertiesCallback,
            PGMEOnDeleteRtmChannelPropertiesCallback onDeleteRtmChannelPropertiesCallback,
            PGMEOnGetRtmChannelHistoryMessagesCallback onGetRtmChannelHistoryMessagesCallback,
            PGMEOnRtmChannelPlayerPropertiesChangedCallback onRtmChannelPlayerPropertiesChangedCallback,
            PGMEOnRtmChannelPropertiesChangedCallback onRtmChannelPropertiesChangedCallback,
            PGMEOnStartDetectAudioFileCallback startDetectAudioFileCallback
        );

        [DllImport("__Internal")]
        internal static extern int CreateHWPGMEngine(IntPtr native, string agcAppId, string clientId,
            string clientSecret, string apiKey, string cpAccessToken, bool logEnable, string logPath, int logSize,
            string openId, string sign, string nonce, string timeStamp);

        [DllImport("__Internal")]
        internal static extern void JoinTeamRoomNative(IntPtr native, string roomId);

        [DllImport("__Internal")]
        internal static extern void JoinNationalRoomNative(IntPtr native, string roomId, int roleType);

        [DllImport("__Internal")]
        internal static extern void JoinRangeRoomNative(IntPtr native, string roomId);

        [DllImport("__Internal")]
        internal static extern void LeaveRoomNative(IntPtr native, string roomId, string ownerId);

        [DllImport("__Internal")]
        internal static extern void SwitchRoomNative(IntPtr native, string roomId);

        [DllImport("__Internal")]
        internal static extern int EnableMicNative(IntPtr native, bool isEnabled);

        [DllImport("__Internal")]
        internal static extern void MutePlayerNative(IntPtr native, string roomId, string openId, bool isMuted);

        [DllImport("__Internal")]
        internal static extern void MuteAllPlayersNative(IntPtr native, string roomId, bool isMuted);

        [DllImport("__Internal")]
        internal static extern void ForbidAllPlayersNative(IntPtr native, string roomId, bool isForbidden);

        [DllImport("__Internal")]
        internal static extern void ForbidPlayerNative(IntPtr native, string roomId, string openId, bool isForbidden);

        [DllImport("__Internal")]
        internal static extern void EnableSpeakerDetectionNative(IntPtr native, int interval);

        [DllImport("__Internal")]
        internal static extern void TransferOwnerNative(IntPtr native, string roomId, string ownerId);

        [DllImport("__Internal")]
        internal static extern void DestroyNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern string GetVersionNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern string GetRoomNative(IntPtr native, string roomId);

        [DllImport("__Internal")]
        internal static extern int EnableVoiceConversionNative(IntPtr native, string roomId, int voiceType);

        [DllImport("__Internal")]
        internal static extern int GetVoiceConversionTypeNative(IntPtr native, string roomId);

        [DllImport("__Internal")]
        internal static extern int EnableEarsBackNative(IntPtr native, bool enable);

        [DllImport("__Internal")]
        internal static extern bool IsEarsBackEnableNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern void StartRecordAudioToTextNative(IntPtr native, string languageCode);

        [DllImport("__Internal")]
        internal static extern void StopRecordAudioToTextNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern void StartRecordAudioMsgNative(IntPtr native, string filePath);

        [DllImport("__Internal")]
        internal static extern void StartRecordAudioMsgWithVoiceTypeNative(IntPtr native, string filePath, int voiceType);

        [DllImport("__Internal")]
        internal static extern void StopRecordAudioMsgNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern void UploadAudioMsgFileNative(IntPtr native, string filePath, int msTimeOut);

        [DllImport("__Internal")]
        internal static extern void DownloadAudioMsgFileNative(IntPtr native, string fileId, string filePath,
            int msTimeOut);

        [DllImport("__Internal")]
        internal static extern string GetAudioMsgFileInfoNative(IntPtr native, string filePath);

        [DllImport("__Internal")]
        internal static extern void PlayAudioMsgNative(IntPtr native, string filePath);

        [DllImport("__Internal")]
        internal static extern void StopPlayAudioMsgNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern void StartDetectAudioFileNative(IntPtr native, string fileId);

        [DllImport("__Internal")]
        internal static extern int PlayLocalAudioClipNative(IntPtr native, int soundId, string filePath, int loop,
            int volume);

        [DllImport("__Internal")]
        internal static extern int StopLocalAudioClipNative(IntPtr native, int soundId);

        [DllImport("__Internal")]
        internal static extern int StopAllLocalAudioClipsNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern int PauseLocalAudioClipNative(IntPtr native, int soundId);

        [DllImport("__Internal")]
        internal static extern int PauseAllLocalAudioClipsNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern int ResumeLocalAudioClipNative(IntPtr native, int soundId);


        [DllImport("__Internal")]
        internal static extern int ResumeAllLocalAudioClipsNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern int GetVolumeOfLocalAudioClipNative(IntPtr native, int soundId);

        [DllImport("__Internal")]
        internal static extern int GetLocalAudioClipsVolumeNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern int SetVolumeOfLocalAudioClipNative(IntPtr native, int soundId, int volume);

        [DllImport("__Internal")]
        internal static extern int SetLocalAudioClipsVolumeNative(IntPtr native, int volume);

        [DllImport("__Internal")]
        internal static extern int SetAudioRecvRangeNative(IntPtr native, int range);

        [DllImport("__Internal")]
        internal static extern void ClearAllRemotePositionsNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern void ClearRemotePlayerPositionNative(IntPtr native, string openId);

        [DllImport("__Internal")]
        internal static extern int InitSpatialSoundNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern int EnableSpatialSoundNative(IntPtr native, string roomId, bool enable);

        [DllImport("__Internal")]
        internal static extern bool IsEnableSpatialSoundNative(IntPtr native, string roomId);

        [DllImport("__Internal")]
        internal static extern int UpdateSelfPositionNative(IntPtr native, string position);

        [DllImport("__Internal")]
        internal static extern int UpdateRemotePositionNative(IntPtr native, string positions);

        #region rtm

        [DllImport("__Internal")]
        internal static extern void SubscribeRtmChannelNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void UnSubscribeRtmChannelNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern string GetRtmSubscribedChannelInfoNative(IntPtr native);

        [DllImport("__Internal")]
        internal static extern void GetRtmChannelInfoNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern string PublishRtmChannelMessageNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern string PublishRtmPeerMessageNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void SetRtmChannelPlayerPropertiesNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void GetRtmChannelPlayerPropertiesNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void DeleteRtmChannelPlayerPropertiesNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void SetRtmChannelPropertiesNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void GetRtmChannelPropertiesNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void DeleteRtmChannelPropertiesNative(IntPtr native, string req);

        [DllImport("__Internal")]
        internal static extern void GetRtmChannelHistoryMessagesNative(IntPtr native, string req);

        #endregion

        #endregion

        private static GameMediaEngineForIos sInstance = new GameMediaEngineForIos();

        private GameMediaEngineForIos()
        {
            this.unityPtr = (IntPtr) GCHandle.Alloc(this);
        }

        public static GameMediaEngineForIos GetInstance()
        {
            if (sInstance == null)
            {
                sInstance = new GameMediaEngineForIos();
            }

            return sInstance;
        }

        public GameMediaEngine CreateEngine(EngineCreateParams engineParams, IGameMMEEventHandler callBackHandler)
        {
            this.pgmePtr = InitHWPGMENative(unityPtr);
            this.callBackHandler = callBackHandler;

            SetNativeCallbacks(this.pgmePtr, NativeOnCreateCallback, NativeOnLeaveRoomCallback,
                NativeOnJoinTeamRoomCallback,
                NativeOnJoinNationalRoomCallback, NativeOnForbidPlayerCallback, NativeOnForbidAllPlayersCallback,
                NativeOnMutePlayerCallback,
                NativeOnMuteAllPlayersCallback, NativeOnPlayerOnlineCallback, NativeOnPlayerOfflineCallback,
                NativeOnDestoryCallback, NativeOnSpeakerDetectionExCallback, NativeOnForbiddenByOwnerCallback,
                NativeOnSwitchRoomCallback, NativeOnTransferOwnerCallback, NativeOnVoiceToTextCallback,
                NativeOnRemoteMicroStateChangedCallback,
                NativeOnUploadAudioMsgFileCallback, NativeOnDownloadAudioMsgFileCallback,
                NativeOnRecordAudioMsgCallback, NativeOnPlayAudioMsgCallback,
                NativeOnAudioClipStateChangedNotifyCallback,
                NativeOnJoinRangeRoomCallback,
                NativeOnSubscribeRtmChannelCallback,
                NativeOnUnSubscribeRtmChannelCallback,
                NativeOnPublishRtmChannelMessageCallback,
                NativeOnPublishRtmPeerMessageCallback,
                NativeOnGetRtmChannelInfoCallback,
                NativeOnReceiveRtmChannelMessageCallback,
                NativeOnReceiveRtmPeerMessageCallback,
                NativeOnRtmConnectionChangedCallback,
                NativeOnSetRtmChannelPlayerPropertiesCallback,
                NativeOnGetRtmChannelPlayerPropertiesCallback,
                NativeOnDeleteRtmChannelPlayerPropertiesCallback,
                NativeOnSetRtmChannelPropertiesCallback,
                NativeOnGetRtmChannelPropertiesCallback,
                NativeOnDeleteRtmChannelPropertiesCallback,
                NativeOnGetRtmChannelHistoryMessagesCallback,
                NativeOnRtmChannelPlayerPropertiesChangedCallback,
                NativeOnRtmChannelPropertiesChangedCallback,
                NativeOnStartDetectAudioFileCallback
            );

            int ret = CreateHWPGMEngine(this.pgmePtr, engineParams.AppId, engineParams.ClientId,
                engineParams.ClientSecret, engineParams.ApiKey,
                engineParams.CpAccessToken, engineParams.LogEnable, engineParams.LogPath, engineParams.LogSize,
                engineParams.OpenId, engineParams.Sign,
                engineParams.Nonce, engineParams.Timestamp);
            if (ret != 0)
            {
                Debug.Log("GMMEEngine create is null");
                return null;
            }

            Debug.Log("GMMEEngine create success");
            return sInstance;
        }

        public void DestroyEngine()
        {
            DestroyNative(this.pgmePtr);
        }

        public override void JoinTeamRoom(string roomId)
        {
            JoinTeamRoomNative(this.pgmePtr, roomId);
        }

        public override void JoinNationalRoom(string roomId, int roleType)
        {
            JoinNationalRoomNative(this.pgmePtr, roomId, roleType);
        }

        public override void JoinRangeRoom(string roomId)
        {
            JoinRangeRoomNative(this.pgmePtr, roomId);
        }

        public override void SwitchRoom(string roomId)
        {
            SwitchRoomNative(this.pgmePtr, roomId);
        }

        public override void LeaveRoom(string roomId, string ownerId)
        {
            LeaveRoomNative(this.pgmePtr, roomId, ownerId);
        }

        public override void TransferOwner(string roomId, string ownerId)
        {
            TransferOwnerNative(this.pgmePtr, roomId, ownerId);
        }

        public override int EnableMic(bool isEnabled)
        {
            return EnableMicNative(this.pgmePtr, isEnabled);
        }

        public override void MutePlayer(string roomId, string openId, bool isMuted)
        {
            MutePlayerNative(this.pgmePtr, roomId, openId, isMuted);
        }

        public override void MuteAllPlayers(string roomId, bool isMuted)
        {
            MuteAllPlayersNative(this.pgmePtr, roomId, isMuted);
        }

        public override Room GetRoom(string roomId)
        {
            string roomInfo = GetRoomNative(this.pgmePtr, roomId);
            if (!string.IsNullOrEmpty(roomInfo))
            {
                return JsonUtil.FromJson<Room>(roomInfo);
            }

            return null;
        }

        public override int EnableVoiceConversion(string roomId, int voiceType)
        {
            return EnableVoiceConversionNative(this.pgmePtr, roomId, voiceType);
        }

        public override int GetVoiceConversionType(string roomId)
        {
            return GetVoiceConversionTypeNative(this.pgmePtr, roomId);
        }

        public override int EnableEarsBack(bool enable)
        {
            return EnableEarsBackNative(this.pgmePtr, enable);
        }

        public override bool IsEarsBackEnable()
        {
            return IsEarsBackEnableNative(this.pgmePtr);
        }

        public override void EnableSpeakersDetection(string roomId, int interval)
        {
            EnableSpeakerDetectionNative(this.pgmePtr, interval);
        }

        public override void ForbidAllPlayers(string roomId, bool isForbidden)
        {
            ForbidAllPlayersNative(this.pgmePtr, roomId, isForbidden);
        }

        public override void ForbidPlayer(string roomId, string openId, bool isForbidden)
        {
            ForbidPlayerNative(this.pgmePtr, roomId, openId, isForbidden);
        }

        public override void StartRecordAudioToText(VoiceParam voiceParam)
        {
            StartRecordAudioToTextNative(this.pgmePtr, voiceParam.LanguageCode);
        }

        public override void StopRecordAudioToText()
        {
            StopRecordAudioToTextNative(this.pgmePtr);
        }

        public override void StartRecordAudioMsg(string filePath)
        {
            StartRecordAudioMsgNative(this.pgmePtr, filePath);
        }

        public override void StartRecordAudioMsg(string filePath, int voiceType)
        {
            StartRecordAudioMsgWithVoiceTypeNative(this.pgmePtr, filePath, voiceType); 
        }

        public override void StopRecordAudioMsg()
        {
            StopRecordAudioMsgNative(this.pgmePtr);
        }

        public override void UploadAudioMsgFile(string filePath, int msTimeOut)
        {
            UploadAudioMsgFileNative(this.pgmePtr, filePath, msTimeOut);
        }

        public override void DownloadAudioMsgFile(string fileId, string filePath, int msTimeOut)
        {
            DownloadAudioMsgFileNative(this.pgmePtr, fileId, filePath, msTimeOut);
        }

        public override AudioMsgFileInfo GetAudioMsgFileInfo(string filePath)
        {
            string audioMsgFileInfo = GetAudioMsgFileInfoNative(this.pgmePtr, filePath);
            if (!string.IsNullOrEmpty(audioMsgFileInfo))
            {
                return JsonUtil.FromJson<AudioMsgFileInfo>(audioMsgFileInfo);
            }

            return new AudioMsgFileInfo();
        }

        public override void PlayAudioMsg(string filePath)
        {
            PlayAudioMsgNative(this.pgmePtr, filePath);
        }

        public override void StopPlayAudioMsg()
        {
            StopPlayAudioMsgNative(this.pgmePtr);
        }

        public override void StartDetectAudioFile(string fileId)
        {
            StartDetectAudioFileNative(this.pgmePtr, fileId);
        }

        public override int PlayLocalAudioClip(LocalAudioInfo localAudioInfo)
        {
            return PlayLocalAudioClipNative(this.pgmePtr, localAudioInfo.SoundId, localAudioInfo.FilePath,
                localAudioInfo.Loop, localAudioInfo.Volume);
        }

        public override int StopLocalAudioClip(int soundId)
        {
            return StopLocalAudioClipNative(this.pgmePtr, soundId);
        }

        public override int StopAllLocalAudioClips()
        {
            return StopAllLocalAudioClipsNative(this.pgmePtr);
        }

        public override int PauseLocalAudioClip(int soundId)
        {
            return PauseLocalAudioClipNative(pgmePtr, soundId);
        }

        public override int PauseAllLocalAudioClips()
        {
            return PauseAllLocalAudioClipsNative(pgmePtr);
        }

        public override int ResumeLocalAudioClip(int soundId)
        {
            return ResumeLocalAudioClipNative(pgmePtr, soundId);
        }

        public override int ResumeAllLocalAudioClips()
        {
            return ResumeAllLocalAudioClipsNative(pgmePtr);
        }

        public override int GetVolumeOfLocalAudioClip(int soundId)
        {
            return GetVolumeOfLocalAudioClipNative(pgmePtr, soundId);
        }

        public override int GetLocalAudioClipsVolume()
        {
            return GetLocalAudioClipsVolumeNative(pgmePtr);
        }

        public override int SetVolumeOfLocalAudioClip(int soundId, int volume)
        {
            return SetVolumeOfLocalAudioClipNative(pgmePtr, soundId, volume);
        }

        public override int SetLocalAudioClipsVolume(int volume)
        {
            return SetLocalAudioClipsVolumeNative(pgmePtr, volume);
        }

        public override int SetAudioRecvRange(int range)
        {
            return SetAudioRecvRangeNative(pgmePtr, range);
        }

        public override int UpdateSelfPosition(SelfPosition selfPosition)
        {
            return UpdateSelfPositionNative(pgmePtr, JsonUtil.ToJson(selfPosition));
        }

        public override int UpdateRemotePosition(RemotePlayerPosition[] positions)
        {
            return UpdateRemotePositionNative(pgmePtr, JsonUtil.ToJson(positions));
        }

        public override void ClearAllRemotePositions()
        {
            ClearAllRemotePositionsNative(pgmePtr);
        }

        public override void ClearRemotePlayerPosition(string openId)
        {
            ClearRemotePlayerPositionNative(pgmePtr, openId);
        }

        public override int InitSpatialSound()
        {
            return InitSpatialSoundNative(pgmePtr);
        }

        public override int EnableSpatialSound(string roomId, bool enable)
        {
            return EnableSpatialSoundNative(pgmePtr, roomId, enable);
        }

        public override bool IsEnableSpatialSound(string roomId)
        {
            return IsEnableSpatialSoundNative(pgmePtr, roomId);
        }


        #region rtm

        /**
         * 订阅RTM频道
         *
         * @param req 订阅RTM频道请求对象
         */
        public override void SubscribeRtmChannel(SubscribeRtmChannelReq req)
        {
            Debug.Log("SubscribeRtmChannel is called in the ios sdk");
            SubscribeRtmChannelNative(pgmePtr, req.ConvertToJson());
        }

        /**
         * 取消订阅RTM频道
         *
         * @param req 取消订阅RTM频道请求对象
         */
        public override void UnSubscribeRtmChannel(UnSubscribeRtmChannelReq req)
        {
            Debug.Log("UnSubscribeRtmChannel is called in the ios sdk");
            UnSubscribeRtmChannelNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 查询已订阅RTM频道信息
         *
         * @return 已订阅频道结果
         */
        public override GetRtmSubscribedChannelInfoResult GetRtmSubscribedChannelInfo()
        {
            Debug.Log("GetRtmSubscribedChannelInfo is called in the ios sdk");
            string result = GetRtmSubscribedChannelInfoNative(pgmePtr);

            if (!string.IsNullOrEmpty(result))
            {
                return JsonUtil.FromJson<GetRtmSubscribedChannelInfoResult>(result);
            }

            return null;
        }

        /**
         * 查询RTM频道信息
         *
         * @param req 查询RTM频道信息请求对象
         */
        public override void GetRtmChannelInfo(GetRtmChannelInfoReq req)
        {
            Debug.Log("GetRtmChannelInfo is called in the ios sdk");
            GetRtmChannelInfoNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 发布RTM频道信息
         *
         * @param req 发布RTM频道信息请求对象
         * @return 客户端本地生成的 clientMsgId
         */
        public override string PublishRtmChannelMessage(PublishRtmChannelMessageReq req)
        {
            Debug.Log("PublishRtmChannelMessage is called in the ios sdk");
            return PublishRtmChannelMessageNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 发布RTM点对点信息
         *
         * @param req 发布RTM点对点信息请求对象
         * @return 客户端本地生成的 clientMsgId
         */
        public override string PublishRtmPeerMessage(PublishRtmPeerMessageReq req)
        {
            Debug.Log("PublishRtmPeerMessage is called in the ios sdk");
            return PublishRtmPeerMessageNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 设置RTM频道内玩家属性
         *
         * @param req 设置RTM频道内玩家属性请求对象
         */
        public override void SetRtmChannelPlayerProperties(SetRtmChannelPlayerPropertiesReq req)
        {
            Debug.Log("SetRtmChannelPlayerProperties is called in the ios sdk");
            SetRtmChannelPlayerPropertiesNative(pgmePtr, req.ConvertToJson());
        }

        /**
         * 查询RTM频道内玩家属性
         *
         * @param req 查询RTM频道内玩家属性请求对象
         */
        public override void GetRtmChannelPlayerProperties(GetRtmChannelPlayerPropertiesReq req)
        {
            Debug.Log("GetRtmChannelPlayerProperties is called in the ios sdk");
            GetRtmChannelPlayerPropertiesNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 删除RTM频道内玩家属性
         *
         * @param req 删除RTM频道内玩家属性请求对象
         */
        public override void DeleteRtmChannelPlayerProperties(DeleteRtmChannelPlayerPropertiesReq req)
        {
            Debug.Log("DeleteRtmChannelPlayerProperties is called in the ios sdk");
            DeleteRtmChannelPlayerPropertiesNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 设置RTM频道属性
         *
         * @param req 设置RTM频道属性请求对象
         */
        public override void SetRtmChannelProperties(SetRtmChannelPropertiesReq req)
        {
            Debug.Log("SetRtmChannelProperties is called in the ios sdk");
            SetRtmChannelPropertiesNative(pgmePtr, req.ConvertToJson());
        }

        /**
         * 查询RTM频道属性
         *
         * @param req 查询RTM频道属性请求对象
         */
        public override void GetRtmChannelProperties(GetRtmChannelPropertiesReq req)
        {
            Debug.Log("GetRtmChannelProperties is called in the ios sdk");
            GetRtmChannelPropertiesNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 删除RTM频道属性
         *
         * @param req 删除RTM频道属性请求对象
         */
        public override void DeleteRtmChannelProperties(DeleteRtmChannelPropertiesReq req)
        {
            Debug.Log("DeleteRtmChannelProperties is called in the ios sdk");
            DeleteRtmChannelPropertiesNative(pgmePtr, JsonUtil.ToJson(req));
        }

        /**
         * 查询RTM频道历史消息
         *
         * @param req 查询RTM频道历史消息请求对象
         */
        public override void GetRtmChannelHistoryMessages(GetRtmChannelHistoryMessagesReq req)
        {
            Debug.Log("GetRtmChannelHistoryMessages is called in the ios sdk");
            GetRtmChannelHistoryMessagesNative(pgmePtr, JsonUtil.ToJson(req));
        }

        #endregion


        #region native callback methods impl

        [AOT.MonoPInvokeCallback(typeof(PGMEOnCreateCallback))]
        private static void NativeOnCreateCallback(IntPtr unityClient, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onCreate(code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnLeaveRoomCallback))]
        private static void NativeOnLeaveRoomCallback(IntPtr unityClient, string roomId, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onLeaveRoom(roomId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnJoinTeamRoomCallback))]
        private static void NativeOnJoinTeamRoomCallback(IntPtr unityClient, string roomId, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onJoinTeamRoom(roomId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnJoinNationalRoomCallback))]
        private static void NativeOnJoinNationalRoomCallback(IntPtr unityClient, string roomId, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onJoinNationalRoom(roomId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnJoinRangeRoomCallback))]
        private static void NativeOnJoinRangeRoomCallback(IntPtr unityClient, string roomId, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onJoinRangeRoom(roomId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnForbidPlayerCallback))]
        private static void NativeOnForbidPlayerCallback(IntPtr unityClient, string roomId, string openId,
            bool isForbidden, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onForbidPlayer(roomId, openId, isForbidden, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnForbidAllPlayersCallback))]
        private static void NativeOnForbidAllPlayersCallback(IntPtr unityClient, string roomId, string openIds,
            bool isForbidden, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onForbidAllPlayers(roomId, openIds, isForbidden, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnMutePlayerCallback))]
        private static void NativeOnMutePlayerCallback(IntPtr unityClient, string roomId, string openId, bool isMuted,
            int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onMutePlayer(roomId, openId, isMuted, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnMuteAllPlayersCallback))]
        private static void NativeOnMuteAllPlayersCallback(IntPtr unityClient, string roomId, string openIds,
            bool isMuted, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onMuteAllPlayers(roomId, openIds, isMuted, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnPlayerOnlineCallback))]
        private static void NativeOnPlayerOnlineCallback(IntPtr unityClient, string roomId, string openId)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onPlayerOnline(roomId, openId);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnPlayerOfflineCallback))]
        private static void NativeOnPlayerOfflineCallback(IntPtr unityClient, string roomId, string openId)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onPlayerOffline(roomId, openId);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnDestoryCallback))]
        private static void NativeOnDestoryCallback(IntPtr unityClient, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onDestroy(code, msg);
        }


        [AOT.MonoPInvokeCallback(typeof(PGMEOnSpeakerDetectionExCallback))]
        private static void NativeOnSpeakerDetectionExCallback(IntPtr unityClient, string userVolumeInfos)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onSpeakersDetectionEx(userVolumeInfos);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnForbiddenByOwnerCallback))]
        private static void NativeOnForbiddenByOwnerCallback(IntPtr unityClient, string roomId, string openIds,
            bool isForbidden)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onForbiddenByOwner(roomId, openIds, isForbidden);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnSwitchRoomCallback))]
        private static void NativeOnSwitchRoomCallback(IntPtr unityClient, string roomId, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onSwitchRoom(roomId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnTransferOwnerCallback))]
        private static void NativeOnTransferOwnerCallback(IntPtr unityClient, string roomId, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onTransferOwner(roomId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnVoiceToTextCallback))]
        private static void NativeOnVoiceToTextCallback(IntPtr unityClient, string text, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onVoiceToText(text, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnRemoteMicroStateChangedCallback))]
        private static void NativeOnRemoteMicroStateChangedCallback(IntPtr unityClient, string roomId, string openId,
            bool isMute)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onRemoteMicroStateChanged(roomId, openId, isMute);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnUploadAudioMsgFileCallback))]
        private static void NativeOnUploadAudioMsgFileCallback(IntPtr unityClient, string filePath, string fileId,
            int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onUploadAudioMsgFile(filePath, fileId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnDownloadAudioMsgFileCallback))]
        private static void NativeOnDownloadAudioMsgFileCallback(IntPtr unityClient, string filePath, string fileId,
            int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onDownloadAudioMsgFile(filePath, fileId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnRecordAudioMsgCallback))]
        private static void NativeOnRecordAudioMsgCallback(IntPtr unityClient, string filePath, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onRecordAudioMsg(filePath, code, msg);
        }


        [AOT.MonoPInvokeCallback(typeof(PGMEOnPlayAudioMsgCallback))]
        private static void NativeOnPlayAudioMsgCallback(IntPtr unityClient, string filePath, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onPlayAudioMsg(filePath, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnStartDetectAudioFileCallback))]
        private static void NativeOnStartDetectAudioFileCallback(IntPtr unityClient, string fileId, int code, string msg)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onStartDetectAudioFile(fileId, code, msg);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnAudioClipStateChangedNotifyCallback))]
        private static void NativeOnAudioClipStateChangedNotifyCallback(IntPtr unityClient, string audioPlayStateInfo)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onAudioClipStateChangedNotify(audioPlayStateInfo);
        }

        #region rtm

        [AOT.MonoPInvokeCallback(typeof(PGMEOnSubscribeRtmChannelCallback))]
        private static void NativeOnSubscribeRtmChannelCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onSubscribeRtmChannel(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnUnSubscribeRtmChannelCallback))]
        private static void NativeOnUnSubscribeRtmChannelCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onUnSubscribeRtmChannel(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnPublishRtmChannelMessageCallback))]
        private static void NativeOnPublishRtmChannelMessageCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onPublishRtmChannelMessage(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnPublishRtmPeerMessageCallback))]
        private static void NativeOnPublishRtmPeerMessageCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onPublishRtmPeerMessage(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnGetRtmChannelInfoCallback))]
        private static void NativeOnGetRtmChannelInfoCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onGetRtmChannelInfo(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnReceiveRtmChannelMessageCallback))]
        private static void NativeOnReceiveRtmChannelMessageCallback(IntPtr unityClient, string notify)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onReceiveRtmChannelMessage(notify);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnReceiveRtmPeerMessageCallback))]
        private static void NativeOnReceiveRtmPeerMessageCallback(IntPtr unityClient, string notify)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onReceiveRtmPeerMessage(notify);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnRtmConnectionChangedCallback))]
        private static void NativeOnRtmConnectionChangedCallback(IntPtr unityClient, string notify)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onRtmConnectionChanged(notify);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnSetRtmChannelPlayerPropertiesCallback))]
        private static void NativeOnSetRtmChannelPlayerPropertiesCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onSetRtmChannelPlayerProperties(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnGetRtmChannelPlayerPropertiesCallback))]
        private static void NativeOnGetRtmChannelPlayerPropertiesCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onGetRtmChannelPlayerProperties(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnDeleteRtmChannelPlayerPropertiesCallback))]
        private static void NativeOnDeleteRtmChannelPlayerPropertiesCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onDeleteRtmChannelPlayerProperties(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnSetRtmChannelPropertiesCallback))]
        private static void NativeOnSetRtmChannelPropertiesCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onSetRtmChannelProperties(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnGetRtmChannelPropertiesCallback))]
        private static void NativeOnGetRtmChannelPropertiesCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onGetRtmChannelProperties(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnDeleteRtmChannelPropertiesCallback))]
        private static void NativeOnDeleteRtmChannelPropertiesCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onDeleteRtmChannelProperties(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnGetRtmChannelHistoryMessagesCallback))]
        private static void NativeOnGetRtmChannelHistoryMessagesCallback(IntPtr unityClient, string result)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onGetRtmChannelHistoryMessages(result);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnRtmChannelPlayerPropertiesChangedCallback))]
        private static void NativeOnRtmChannelPlayerPropertiesChangedCallback(IntPtr unityClient, string notify)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onRtmChannelPlayerPropertiesChanged(notify);
        }

        [AOT.MonoPInvokeCallback(typeof(PGMEOnRtmChannelPropertiesChangedCallback))]
        private static void NativeOnRtmChannelPropertiesChangedCallback(IntPtr unityClient, string notify)
        {
            GameMediaEngineForIos client = IntPtrToUnityClient(unityClient);
            client.callBackHandler?.onRtmChannelPropertiesChanged(notify);
        }

        #endregion

        #endregion

        private static GameMediaEngineForIos IntPtrToUnityClient(IntPtr unityPtr)
        {
            GCHandle handle = (GCHandle) unityPtr;
            return handle.Target as GameMediaEngineForIos;
        }
    }
}
#endif